﻿namespace EFS.RC.CCC.Application.EndPoints
{
	/// <summary>
	/// Application end point
	/// </summary>
	internal abstract class EndPoint : EFS.RC.Common.AsyncRoot
	{
		// End point setting
		private Microsoft.Rtc.Collaboration.ApplicationEndpointSettings applicationEndpointSettings = null;

		// End point
		private Microsoft.Rtc.Collaboration.ApplicationEndpoint applicationEndpoint = null;

		// End point events deltgates
		protected delegate void EndPointEvent(Microsoft.Rtc.Collaboration.ApplicationEndpoint applicationEndpoint);

		/// <summary>
		/// End point delegates
		/// </summary>
		protected EndPointEvent OnPreEndPointStartup = null;
		protected EndPointEvent OnEndPointActive = null;
		protected EndPointEvent OnPreEndPointShutDown = null;
		protected EndPointEvent OnEndPointStopped = null;

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="ownerUri"></param>
		/// <param name="applicationEndpointSettings"></param>
		public EndPoint(Microsoft.Rtc.Collaboration.ApplicationEndpointSettings applicationEndpointSettings)
		{
			// check
			EFS.Common.Verify.Reference(applicationEndpointSettings, "applicationEndpointSettings");

			// keep settings
			this.applicationEndpointSettings = applicationEndpointSettings;

			// end point setup
			OnPreEndPointStartup += SetupEndPoint;
		}

		// End point
		public Microsoft.Rtc.Collaboration.ApplicationEndpoint CollaborationApplicationEndpoint
		{
			get { return applicationEndpoint;  }
		}

		/// <summary>
		/// Describe this object
		/// </summary>
		/// <returns></returns>
		public override System.String Describe()
		{
			return System.String.Format("EFS.RC.CCC.Application.EndPoints.EndPoint {0}", applicationEndpointSettings.OwnerUri);
		}

		/// <summary>
		/// Begin platform startup
		/// </summary>
		public EFS.RC.Common.AsyncProcess BeginStartup()
		{
			// log
			EFS.EventLog.Log.LogInfo("BeginStartup", this);

			// start end point
			return BeginAsyncProcess(Startup, OnStartupComplete);
		}

		/// <summary>
		/// Begin platform startup
		/// </summary>
		public EFS.RC.Common.AsyncProcess BeginShutdown()
		{
			// log
			EFS.EventLog.Log.LogInfo("BeginStartup", this);

			// start end point
			return BeginAsyncProcess(Shutdown, OnShutdownComplete);
		}

		#region Startup

		/// <summary>
		/// Platform startup
		/// </summary>
		private void Startup()
		{
			// new app end point
			applicationEndpoint = new Microsoft.Rtc.Collaboration.ApplicationEndpoint(EFS.RC.CCC.Platform.Instance.CollaborationPlatform, applicationEndpointSettings);

			// call setup delegates
			if (null != OnPreEndPointStartup)
			{
				OnPreEndPointStartup(applicationEndpoint);
			}

			// sstablish
			applicationEndpoint.BeginEstablish(OnEstablishComplete, null);
		}

		/// <summary>
		/// Setup end point 
		/// </summary>
		private void SetupEndPoint(Microsoft.Rtc.Collaboration.ApplicationEndpoint applicationEndpoint)
		{
			// get state changes
			applicationEndpoint.StateChanged += OnStateChanged;
		}

		/// <summary>
		/// Start-up complete
		/// </summary>
		/// <param name="ar"></param>
		private void OnStartupComplete(EFS.RC.Common.AsyncProcess ap)
		{
			// log
			EFS.EventLog.Log.LogInfo("OnStartupComplete", this);

			try
			{
				// check
				ap.Throw();

				// log
				EFS.EventLog.Log.LogInfo("OnStartupComplete SUCCCESS", this);
			}
			catch (System.Exception ex)
			{
				// log
				EFS.EventLog.Log.LogException(ex, this);
			}
		}

		/// <summary>
		/// End point established
		/// </summary>
		/// <param name="result"></param>
		private void OnEstablishComplete(System.IAsyncResult ar)
		{
			// log
			EFS.EventLog.Log.LogInfo("OnEstablishComplete", this);

			try
			{
				// make sure all ok
				applicationEndpoint.EndEstablish(ar);

				// log
				EFS.EventLog.Log.LogInfo("OnEstablishComplete SUCCCESS", this);

				// call active delegates
				if (null != OnEndPointActive)
				{
					OnEndPointActive(applicationEndpoint);
				}
			}
			catch (System.Exception ex)
			{
				// log
				EFS.EventLog.Log.LogException(ex, this);
			}
		}

		#endregion Startup

		#region Runtime

		/// <summary>
		/// State changed evensnts
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="args"></param>
		private void OnStateChanged(object sender, Microsoft.Rtc.Collaboration.LocalEndpointStateChangedEventArgs args)
		{
			// check for removed end point and get it down
			if (args.Reason == Microsoft.Rtc.Collaboration.LocalEndpointStateTransitionReason.OwnerDisabledOrRemoved)
			{
				// get down
				// TODO remove end point from the list
			}
		}

		#endregion Runtime
	
		#region Shutdown

		/// <summary>
		/// Sht down
		/// </summary>
		private void Shutdown()
		{
			// log
			EFS.EventLog.Log.LogInfo("Shutdown", this);

			// call shut down delegates
			if (null != OnPreEndPointShutDown)
			{
				OnPreEndPointShutDown(applicationEndpoint);
			}

			// terminate app
			System.IAsyncResult arTerminate = applicationEndpoint.BeginTerminate(null, null);

			// wait terminate
			applicationEndpoint.EndTerminate(arTerminate);
		}

		/// <summary>
		/// Shut down complete
		/// </summary>
		/// <param name="ar"></param>
		private void OnShutdownComplete(EFS.RC.Common.AsyncProcess ap)
		{
			// log
			EFS.EventLog.Log.LogInfo("OnShutdownComplete", this);

			try
			{
				// check
				ap.Throw();

				// log
				EFS.EventLog.Log.LogInfo("OnShutdownComplete SUCCCESS", this);

				// call stopped  delegates
				if (null != OnEndPointStopped)
				{
					OnEndPointStopped(applicationEndpoint);
				}
			}
			catch (System.Exception ex)
			{
				// log
				EFS.EventLog.Log.LogException(ex, this);
			}
		}

		#endregion // shutdown

	}
}
